package com.elinkway.infinitemovies.download;

import android.os.AsyncTask;
import android.text.TextUtils;

import com.elinkway.infinitemovies.application.MoviesApplication;
import com.elinkway.infinitemovies.bean.PlayStatusReporter;
import com.elinkway.infinitemovies.bean.VStreamInfoList;
import com.elinkway.infinitemovies.http.requesttask.ReportPlayStatusTask;
import com.elinkway.infinitemovies.ui.activity.play.PlayerUtils;
import com.elinkway.infinitemovies.utils.LogCat;
import com.elinkway.infinitemovies.utils.LogUtils;
import com.elinkway.infinitemovies.utils.NetWorkTypeUtils;
import com.elinkway.infinitemovies.utils.StringUtil;
import com.elinkway.infinitemovies.utils.Utils;
import com.elinkway.infinitemovies.view.DefinitionManager;

import org.apache.http.conn.ConnectTimeoutException;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

    private final static String TAG = "DownloadTask";
    private DownloadJob mJob;

    private ArrayList<HashMap<String, String>> mDownloadUrls;
    private String mMd5;
    private long mGSize;
    private List<String> mResultUrlList;
    private DownloadEntity mDownloadEntity;
    private PlayStatusReporter mPlayStatusReport = new PlayStatusReporter();

    private int retryCount = 0;
    private static final int MAX_RETRY_COUNT = 2;

    public DownloadTask(DownloadJob job) {
        mJob = job;
        mDownloadUrls = new ArrayList();
        mDownloadEntity = mJob.getEntity();
    }

    /**
     * 设置外站源下载urlList
     *
     * @param resultUrl
     */
    public void setmResultUrlList(List<String> resultUrl) {
        mResultUrlList = resultUrl;
    }

    public void setmPlayStatusReport(PlayStatusReporter mPlayStatusReport) {
        this.mPlayStatusReport = mPlayStatusReport;
    }

    /**
     * 在 mJob.downloadFile()之前设置下载参数
     *
     * @param key 类型
     * @param url 下载地址
     */
    private void setUrl(String key, String url) {
        HashMap<String, String> urlMap = new HashMap<String, String>();
        urlMap.put(key, url);
        mPlayStatusReport.setSetUrlTime(System.currentTimeMillis());
        mJob.setmPlayStatusReport(mPlayStatusReport);
        mDownloadUrls.add(urlMap);
    }

    private void setMd5(String md5) {
        mMd5 = md5;
    }

    private void setGSize(long gSize) {
        mGSize = gSize;
    }

    @Override
    protected void onPreExecute() {
        mJob.notifyDownloadStarted();
        super.onPreExecute();
    }

    @Override
    public void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        if (result) {
            LogUtils.i(CDNDownloadHandler.TAG, "下载成功：" + result + "and current success job is" + mDownloadEntity.getDisplayName());
            mJob.onCompleted();
        } else {
            /**
             * 暂停任务时候发生异常返回false的处理
             */
            if (mJob.getStatus() == DownloadJob.PAUSE) {
                LogUtils.d(CDNDownloadHandler.TAG, "-----------");
                return;
            }
            mJob.setFail(true);
            LogUtils.d(CDNDownloadHandler.TAG, "---------download fail and setFail is true, the mIsFail is:" + mJob.isFail());
            mJob.onFailure();
        }
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            return downloadFile(mJob);
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
            return false;
        } catch (ConnectTimeoutException e) {
            e.printStackTrace();
            return false;
        } catch (Exception e) {
            if (e.toString().contains("No space left on device")) {
                mJob.setExceptionType(DownloadJob.SD_SPACE_FULL);
            } else if (e.toString().contains("java.io.FileNotFoundException")
                    || e.toString().contains("java.io.IOException: write failed: EIO (I/O error)")) {
                mJob.setExceptionType(DownloadJob.NO_SD);// 没有sdcard，或者sdcard拔出或者存储器模式
            }
            e.printStackTrace();
            LogCat.e(Utils.DOWN_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!DownloadTask doInBackground exception!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            LogCat.e(Utils.DOWN_TAG, "!!!!!!!!!!!Exception err info is " + e.getMessage());
            return false;
        }
    }

    @Override
    protected void onCancelled() {
        MoviesApplication.getInstance().getDownloadManager().notifyObservers();
        super.onCancelled();
    }

    private Boolean downloadFile(DownloadJob job) throws Exception {
        // 3g网络时默认不开启下载
        if (NetWorkTypeUtils.reportNetType(MoviesApplication.getInstance()) != 1
                && (!mJob.isDownloadcan3g())) {
            mJob.setExceptionType(DownloadJob.OTHER_EXCEP);
            LogUtils.i(CDNDownloadHandler.TAG, "3g not allow down");
            return false;
        }

//        if(job.getStreamList() != null && job.getStreamList().size() > 1) {
//            mDownloadEntity.setMp4Slice("1");
//            MoviesApplication.getInstance().getDownloadManager().getProvider().updateDownloadEntity(mJob);
//        }
        // 获取下载地址等信息，获取下载地址失败，返回false；
        if (!initDownload()) {
            LogUtils.i(CDNDownloadHandler.TAG, "$$$$$$$$$$$$$$$$$$not init download$$$$$$$$$$$$$$$$$$");
            return false;
        }

        int result = 0;
        int index = 0;
        LogCat.e(Utils.DOWN_TAG, "mDownloadUrls size is " + mDownloadUrls.size());
        // TODO mDownloadUrls size不为1的情况逻辑
        for (; index < mDownloadUrls.size(); index++) {
            LogUtils.d(CDNDownloadHandler.TAG, "-----------index:" + index + "---------");
            LogUtils.d(CDNDownloadHandler.TAG, "-----------下载一共" + mDownloadUrls.size() + "段. 之前下载到第" + mJob.getCurrentDownloadPiece() + "段------------");
            LogUtils.d(CDNDownloadHandler.TAG, "-----------mJob.isPause() is" + mJob.isPause() + "mJob.isFail() is" + mJob.isFail() + "------------");
            if ((mJob.isPause() || mJob.isFail()) && index != mJob.getCurrentDownloadPiece()) {
                LogUtils.d(CDNDownloadHandler.TAG, "-----------当前下载第" + index + "段------------");
                continue;
            }
            mJob.setIsPause(false);
            mJob.setFail(false);
            mJob.setCurrentDownloadPiece(index);
            mJob.setTotleSizeFromServer(index);
            HashMap map = mDownloadUrls.get(index);
            Iterator iter = map.entrySet().iterator();
            String downLoadType = "";
            String url = "";
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                downLoadType = (String) entry.getKey();
                url = (String) entry.getValue();
            }
            DownloadHandler downloadHandler = null;
            if (downLoadType.equals(DownloadInfo.MP4)) {
                downloadHandler = new CDNDownloadHandler();
            } else {
                downloadHandler = new M3u8DownloadHandler();
            }
            mJob.setDownloadHandler(downloadHandler);
            mDownloadEntity.setDownloadType(downLoadType);
            mDownloadEntity.setDownloadUrl(url);
            mDownloadEntity.setMd5(mMd5);
            mDownloadEntity.setgSize(mGSize);
            if(mDownloadUrls.size() > 1) {
                mDownloadEntity.setMp4Slice("1");
            }else if(mDownloadUrls.size() == 0){
                mDownloadEntity.setMp4Slice("0");
            }

            LogUtils.i(CDNDownloadHandler.TAG, "cur down url is " + url);
            LogUtils.d(DownloadDaoImpl.TAG, "------add download job is:" + job.getEntity().getId() + ",at Download file--------");
            boolean isUpdateJob = mJob.updateDownloadEntity();
            if (!isUpdateJob) { //可能job被删除了
                return false;
            }
            result = mJob.downloadFile();//进入真正的下载
            LogCat.e(Utils.DOWN_TAG, "*********************** stream index is " + mJob.getmCurStreamIndex() + " and " + mDownloadEntity.getDisplayName() + " down status is " + getDownStatus(result)); //mp4正常下载返回成功状态需要下载完成或删除下载任务
            if (result == DownloadHandler.DOWNLOAD_SUCCESS) {
                LogUtils.i(CDNDownloadHandler.TAG, "############ the " + index + " piece video down doned############");
//                break;
                if(index < mDownloadUrls.size() - 1) {
                        continue;
                }
                return true;
            } else if (result == DownloadHandler.DOWNLOAD_URL_VALID || result == DownloadHandler.DOWNLOAD_FILE_ERROR) {
                // 当前下载状态不是手动暂停状态下重试下载
                LogUtils.d(CDNDownloadHandler.TAG, "-------失败后当前job的状态是：" + mJob.getStatus() + "------");
                if (DownloadJob.PAUSE != mJob.getStatus()) {
                    LogUtils.d(CDNDownloadHandler.TAG, "!!!!!!!!!!!!down status is DOWNLOAD_FILE_ERROR and retry down 3 times!!!!!!!!!!!!!");
                    // 下载地址有效，重试3次，如果不成功，就尝试其他流下载
                    for (int j = 0; j < 3; j++) {
                        LogUtils.d(CDNDownloadHandler.TAG, "-----重试，第" + j + "次----");
                        result = mJob.downloadFile();//再次下载
                        if (result == DownloadHandler.DOWNLOAD_SUCCESS) {
                            LogUtils.i(CDNDownloadHandler.TAG, "############ the " + index + " piece video down doned############");
                            if(index < mDownloadUrls.size() - 1) {
                                LogUtils.d(CDNDownloadHandler.TAG, "-----多段流重试成功，重试的是第" + index + "段----");
                                break;
                            } else {
                                return true;
                            }

                        } else if (result == DownloadHandler.DOWNLOAD_URL_VALID || result == DownloadHandler.DOWNLOAD_FILE_ERROR) {
                            if (DownloadJob.PAUSE != mJob.getStatus()) {
                                continue;
                            } else {
                                mJob.setIsPause(true);
                                LogUtils.i(CDNDownloadHandler.TAG, "!!!!!!!!!!重试失败的暂停状态!!!!!!!!!!!!!");
                                break;
                            }
                        }
                    }


                    if (result == DownloadHandler.DOWNLOAD_URL_VALID || result == DownloadHandler.DOWNLOAD_FILE_ERROR) {
                        LogUtils.d(CDNDownloadHandler.TAG, "-----多段流重试成功，返回------");
                        return false;
                    }

                    if (result == DownloadHandler.DOWNLOAD_SUCCESS && index < mDownloadUrls.size() - 1) {
                        LogUtils.d(CDNDownloadHandler.TAG, "-----多段流重试成功，继续下一段下载------");
                        continue;
                    }

                } else {
                    mJob.setIsPause(true);
                    LogUtils.i(CDNDownloadHandler.TAG, "!!!!!!!!!!!!down status is DOWNLOAD_FILE_ERROR but user pause downTask!!!!!!!!!!!!!");
                    break;
                }
            }
        }
        LogUtils.i(CDNDownloadHandler.TAG, "%%%%%%%%%%%%%%%%out site prepare retry other stream  %%%%%%%%%%%%%%%%");
        return false;
    }

    /**
     * 下载初始化 获取下载链接和下载类型
     *
     * @return
     */
    private boolean initDownload() {
        if (null == mJob) {
            return false;
        }
        if (null == mDownloadEntity) {
            return false;
        }
        if (PlayerUtils.isOutSite(mDownloadEntity.getSite()) || ("letv".equals(mDownloadEntity.getSite()) && !"1".equals(mDownloadEntity.getIsletvjiexi()))) {
            LogCat.e(Utils.DOWN_TAG, "!!!!!!!外网下载!!!!!!");
            if (null == mResultUrlList || mResultUrlList.isEmpty()) {
                LogUtils.i(CDNDownloadHandler.TAG, "!!!!!!mResultUrlList is null !!!!!!!");
                return false;
            }
            LogCat.e(Utils.DOWN_TAG, "!!!!!!!!!!!!!!mResultUrlList size is " + mResultUrlList.size() + "\n and mResultUrlList is " + mResultUrlList);
            InputStream is = null;
            URL url = null;
            String str = null;
            // 判断文件类型
            while (retryCount < MAX_RETRY_COUNT) {
                try {
                    url = new URL(mResultUrlList.get(0));
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(6000);
                    conn.setReadTimeout(6000);
                    is = conn.getInputStream();
                    byte[] bytes = new byte[45];
                    is.read(bytes, 0, bytes.length);
                    str = new String(bytes, "UTF-8");
                    LogCat.e(Utils.DOWN_TAG, "!!!!!!!!!!!!judge downfile type str is " + str);
                    if (str.contains(DownloadUtils.M3U8_FILE_MARK)) {
                        setOutSiteDownUrl(DownloadInfo.M3U8, mResultUrlList);
                        return true;
                    } else {
                        setOutSiteDownUrl(DownloadInfo.MP4, mResultUrlList);
                        return true;
                    }
                } catch (java.io.IOException e) {
                    retryCount++;
                    e.printStackTrace();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                        return false;
                    }
                } finally {
                    if (null != is)
                        try {
                            is.close();
                        } catch (IOException e) {
                        }
                }
            }
            return false;
        } else if ("nets".equals(mDownloadEntity.getSite())) {
            LogUtils.d(CDNDownloadHandler.TAG, "!!!!!!!云盘下载!!!!!!");
            DownloadRequestManager downloadRequestManager = new DownloadRequestManager();
//            String resultUrl = downloadRequestManager.getCloudDiskDownloadUrl(mDownloadEntity);
            HashMap<String, String> downloadHashMap = downloadRequestManager.getCloudDiskDownloadUrl(mDownloadEntity);
            mPlayStatusReport = downloadRequestManager.getmPlayStatusReport();
            String resultUrl = downloadHashMap.get("downloadUrl");
            String md5 = downloadHashMap.get("md5");
            String gSize = downloadHashMap.get("gSize");
            if (StringUtil.isEmpty(resultUrl)) {
                LogCat.e(Utils.DOWN_TAG, "nets resultUrl null");
                return false;
            }
            if (StringUtil.isEmpty(md5)) {
                LogUtils.d(CDNDownloadHandler.TAG, "nets md5 null");
                return false;
            }

            if (StringUtil.isEmpty(gSize)) {
                LogUtils.d(CDNDownloadHandler.TAG, "nets gSize null");
                return false;
            }
//            resultUrl = getLinkShellUrl(resultUrl);
            setUrl(DownloadInfo.MP4, resultUrl);
            setMd5(md5);
            setGSize(Long.valueOf(gSize));
        } else if ("letv".equals(mDownloadEntity.getSite()) && "1".equals(mDownloadEntity.getIsletvjiexi())) {
            LogUtils.d(CDNDownloadHandler.TAG, "!!!!!!!lvideo下载!!!!!!");
            DownloadRequestManager downloadRequestManager = new DownloadRequestManager();
            VStreamInfoList data = downloadRequestManager.getDownloadData(mDownloadEntity);
            mPlayStatusReport = downloadRequestManager.getmPlayStatusReport();
            if (null == data) {
                LogUtils.d(CDNDownloadHandler.TAG, "lvideo data null");
                return false;
            }
            String videoCode = DefinitionManager.getLetvVtype(mDownloadEntity.getCurrClarity());
            String resultUrl = "";
//            String md5 = "";
//            long gSize = 0l;
            if (null != data.get(videoCode)) {
                resultUrl = data.get(videoCode).getMainUrl();
                if (TextUtils.isEmpty(resultUrl)) {
//						resultUrl = PlayerP2PDecode.getInstance().getLePlayUrl(url);
                    resultUrl = data.get(videoCode).getBackUrl0();
                    if (TextUtils.isEmpty(resultUrl)) {
                        resultUrl = data.get(videoCode).getBackUrl1();
                        if (TextUtils.isEmpty(resultUrl)) {
                            LogUtils.d(CDNDownloadHandler.TAG, "lvideo resultUrl null");
                            return false;
                        }
                    }
                }
//                md5 = data.get(videoCode).md5;
//                gSize = data.get(videoCode).gsize;
//                if (StringUtil.isEmpty(md5)) {
//                    LogCat.e(Utils.DOWN_TAG, "nets md5 null");
//                    return false;
//                }
//
//                if (gSize <= 0l) {
//                    LogCat.e(Utils.DOWN_TAG, "nets gSize null");
//                    return false;
//                }
            } else {
                LogUtils.d(CDNDownloadHandler.TAG, "lvideo videoCode null");
                return false;
            }
            LogUtils.d(CDNDownloadHandler.TAG, "!!!!!!!lvideo下载url!!!!!!" + resultUrl);
            //            resultUrl = getLinkShellUrl(resultUrl);
            setUrl(DownloadInfo.MP4, resultUrl);
//            setMd5(md5);
//            setGSize(gSize);
        }
        LogUtils.d(DownloadDaoImpl.TAG, "------add download job at initDownload--------");
        mJob.updateDownloadEntity(); // 添加到数据库 dao add操作
        return true;
    }

    /**
     * 下载状态
     *
     * @param result
     * @return
     */
    private String getDownStatus(int result) {
        String status = null;
        switch (result) {
            case 0:
                status = "DOWNLOAD_SUCCESS";
                break;
            case 1:
                status = "DOWNLOAD_URL_VALID";
                break;
            case 2:
                status = "DOWNLOAD_URL_INVALID";
                break;
            case 3:
                status = "DOWNLOAD_FILE_ERROR";
                break;
            default:
                status = "";
        }
        return status;
    }

    /**
     * 设置全部下载url
     *
     * @param downType 下载类型
     * @param downUrl  urlList
     */
    private void setOutSiteDownUrl(String downType, List<String> downUrl) {
        for (String url : downUrl) {
            setUrl(downType, url);
        }
    }

    private void reportPlayState(String state){
        mPlayStatusReport.setState(state);
        new ReportPlayStatusTask(MoviesApplication.getInstance(), mPlayStatusReport).start();
    }
}
